package com.dengbw.systemtransfer.service;

import com.dengbw.systemtransfer.global.CoreKey;
import com.dengbw.systemtransfer.model.CunDepInfo;
import com.dengbw.systemtransfer.model.DepInfo;
import com.dengbw.systemtransfer.model.Information;
import com.dengbw.systemtransfer.model.exceptions.MyRuntimeException;
import com.dengbw.systemtransfer.utils.EasyCacheUtil;
import com.dengbw.systemtransfer.utils.KeyUtils;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.*;
import com.dingtalk.api.response.*;
import com.taobao.api.ApiException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 钉钉的类
 *
 * @author Junyu.Shi
 */
@Slf4j
@Service
public class DingCommonService {

    private static final String DING_ACCESS_TOKEN = "DING_ACCESS_TOKEN_";

    /**
     * 获取系统的主管理员
     */
    public String getAdmin(String accessKey, String accessSecret) {
        String userId = null;
        try {
            DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/user/listadmin");
            OapiUserListadminRequest request = new OapiUserListadminRequest();
            request.setHttpMethod("GET");
            OapiUserListadminResponse response = client.execute(request, getStaticToken(accessKey, accessSecret));
            if (response.isSuccess()) {
                for (OapiUserListadminResponse.ListAdminResponse user : response.getResult()) {
                    if (1 == user.getSysLevel()) {
                        userId = user.getUserid();
                        break;
                    }
                }
            }
            if (StringUtils.isEmpty(userId))
                throw new ApiException("没有成功获取到组织[" + accessKey + "]-[" + accessSecret + "]的管理员信息");
        } catch (ApiException e) {
            log.error("获取组织的管理员信息失败:{},{}", accessKey, accessSecret, e);
            throw new MyRuntimeException("获取组织的管理员信息失败");
        }
        return userId;
    }

    /**
     * 获取应用信息
     */
    public List<OapiMicroappListResponse.Applist> getMicroApp(String accessKey, String accessSecret) {
        List<OapiMicroappListResponse.Applist> appList = new ArrayList<>();
        try {
            DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/microapp/list");
            OapiMicroappListRequest request = new OapiMicroappListRequest();
            request.setHttpMethod("POST");
            OapiMicroappListResponse response = client.execute(request, getStaticToken(accessKey, accessSecret));
            if (response.isSuccess())
                appList.addAll(response.getAppList());
        } catch (ApiException e) {
            log.error("获取组织的应用信息失败:{},{}", accessKey, accessSecret, e);
            throw new MyRuntimeException("获取组织的应用信息失败");
        }
        return appList;
    }

    /**
     * 获取表单信息
     */
    public List<OapiCollectionFormListResponse.FormSchemaResponse> getForm(String accessKey, String accessSecret, Long offset) {
        List<OapiCollectionFormListResponse.FormSchemaResponse> formList = new ArrayList<>();
        try {
            DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/collection/form/list");
            OapiCollectionFormListRequest request = new OapiCollectionFormListRequest();
            request.setHttpMethod("POST");
            request.setOffset(offset);
            request.setSize(200L);
            OapiCollectionFormListResponse response = client.execute(request, getStaticToken(accessKey, accessSecret));
            if (response.isSuccess()) {
                formList.addAll(response.getResult().getList());
                if (Boolean.TRUE.equals(response.getResult().getHasMore()))
                    formList.addAll(getForm(accessKey, accessSecret, offset + 1L));
            }
        } catch (ApiException e) {
            log.error("获取组织的表单信息失败:{},{}", accessKey, accessSecret, e);
            throw new MyRuntimeException("获取组织的表单信息失败");
        }
        return formList;
    }

    /**
     * 获取流程信息
     */
    public List<OapiProcessTemplateManageGetResponse.ProcessSimpleVO> getProcess(String accessKey, String accessSecret, String userId) {
        List<OapiProcessTemplateManageGetResponse.ProcessSimpleVO> processList = new ArrayList<>();
        try {
            DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/process/template/manage/get");
            OapiProcessTemplateManageGetRequest request = new OapiProcessTemplateManageGetRequest();
            request.setHttpMethod("POST");
            request.setUserid(userId);
            OapiProcessTemplateManageGetResponse response = client.execute(request, getStaticToken(accessKey, accessSecret));
            if (response.isSuccess())
                processList.addAll(response.getResult());
        } catch (ApiException e) {
            log.error("获取组织的流程信息失败:{},{}", accessKey, accessSecret, e);
            throw new MyRuntimeException("获取组织的流程信息失败");
        }
        return processList;
    }

    public DepInfo fetchDepInfo(String appKey, String appSecret) {
        DepInfo info = new DepInfo();
        List<OapiV2DepartmentListsubResponse.DeptBaseResponse> deptList = getDepList(1L, appKey, appSecret);
        for (OapiV2DepartmentListsubResponse.DeptBaseResponse dept : deptList) {
            if ("服务支撑人员".equals(dept.getName())) {
                info.setFuwu(dept.getDeptId());
            } else if ("乡镇管理人员".equals(dept.getName())) {
                info.setXiangzhen(dept.getDeptId());
            } else {
                List<OapiV2DepartmentListsubResponse.DeptBaseResponse> subDeptList = getDepList(dept.getDeptId(), appKey, appSecret);
                CunDepInfo cunInfo = new CunDepInfo();
                cunInfo.setCunName(dept.getName());
                cunInfo.setCunDepId(dept.getDeptId());
                for (OapiV2DepartmentListsubResponse.DeptBaseResponse subDept : subDeptList) {
                    if ("服务支撑人员".equals(subDept.getName())) {
                        cunInfo.setFuwu(subDept.getDeptId());
                    } else if ("农户".equals(subDept.getName())) {
                        cunInfo.setNonghu(subDept.getDeptId());
                    }
                }
                info.getCunDepInfoList().add(cunInfo);
            }
        }
        return info;
    }

    public static List<OapiV2DepartmentListsubResponse.DeptBaseResponse> getDepList(long depId, String accessKey, String accessSecret) {
        try {
            DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/listsub");
            OapiV2DepartmentListsubRequest req = new OapiV2DepartmentListsubRequest();
            req.setDeptId(depId);
            req.setLanguage("zh_CN");
            OapiV2DepartmentListsubResponse rsp = client.execute(req, getStaticToken(accessKey, accessSecret));
            return rsp.getResult();
        } catch (ApiException e) {
            e.printStackTrace();
            throw new MyRuntimeException("");
        }
    }

    /**
     * 调用钉钉获取AccessToken备用(由于token每次请求不过期不变，可以多次发送)
     *
     * @return token信息
     */
    public static String getStaticToken(String accessKey, String accessSecret) {
        Object token = EasyCacheUtil.get(DING_ACCESS_TOKEN + accessKey);
        if (null != token) {
            return (String) token;
        } else {
            try {
                DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
                OapiGettokenRequest request = new OapiGettokenRequest();
                request.setAppkey(accessKey);
                request.setAppsecret(accessSecret);
                request.setHttpMethod("GET");
                OapiGettokenResponse response = client.execute(request);
                String accessToken = response.getAccessToken();
                if (StringUtils.isEmpty(accessToken)) {
                    log.error("获取access_token失败，accessKey:{}, accessSecret:{}, 错误信息：{}", accessKey, accessSecret, response.getErrmsg());
                    throw new MyRuntimeException("获取access_token失败，accessKey:" + accessKey + ", accessSecret:" + accessSecret + ", 错误信息：" + response.getErrmsg());
                }
                EasyCacheUtil.put(DING_ACCESS_TOKEN + accessKey, accessToken);
                return accessToken;
            } catch (ApiException e) {
                log.error("获取access_token失败，accessKey:{}, accessSecret:{}", accessKey, accessSecret, e);
                throw new MyRuntimeException("获取access_token失败，accessKey:" + accessKey + ", accessSecret:" + accessSecret + "msg:" + e.getErrMsg());
            }
        }
    }

    public Information fetchInformation(String accessKey, String accessSecret) {
        Information information = new Information();
        information.setManagerId(getAdmin(accessKey, accessSecret));
        List<OapiMicroappListResponse.Applist> appList = getMicroApp(accessKey, accessSecret);
        List<OapiCollectionFormListResponse.FormSchemaResponse> formList = getForm(accessKey, accessSecret, 0L);
        List<OapiProcessTemplateManageGetResponse.ProcessSimpleVO> processList = getProcess(accessKey, accessSecret, information.getManagerId());
        information.setAppList(appList.parallelStream().collect(Collectors.toMap(OapiMicroappListResponse.Applist::getName, e -> e, (v1, v2) -> v1)));
        information.setFormList(formList.parallelStream().collect(Collectors.toMap(OapiCollectionFormListResponse.FormSchemaResponse::getName, e -> e, (v1, v2) -> v1)));
        information.setProcessList(processList.parallelStream().collect(Collectors.toMap(OapiProcessTemplateManageGetResponse.ProcessSimpleVO::getFlowTitle, e -> e, (v1, v2) -> v1)));
        return information;
    }

    public Map<String, String> fetchCore(String appKey, String appSecret) {
        Map<String, String> core = new HashMap<>(17);
        Information information = fetchInformation(appKey, appSecret);
        List<String> cores = KeyUtils.keysOf(CoreKey.class);
        if (cores.isEmpty()) {
            return core;
        }
        cores.forEach(c -> {
            if (information.getAppList().containsKey(c)) {
                core.put(c, String.valueOf(information.getAppList().get(c).getAgentId()));
            } else if (information.getFormList().containsKey(c)) {
                core.put(c, String.valueOf(information.getFormList().get(c).getFormCode()));
            } else if (information.getProcessList().containsKey(c)) {
                core.put(c, String.valueOf(information.getProcessList().get(c).getProcessCode()));
            }
        });
        return core;
    }
}
